package org.wu.framework.authorization.platform.infrastructure.persistence;


import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.wu.framework.authorization.platform.domain.model.sys.interface_.SysInterface;
import org.wu.framework.authorization.platform.domain.model.sys.interface_.SysInterfaceRepository;
import org.wu.framework.authorization.platform.infrastructure.converter.SysInterfaceConverter;
import org.wu.framework.authorization.platform.infrastructure.entity.SysInterfaceDO;
import org.wu.framework.core.utils.ObjectUtils;
import org.wu.framework.lazy.orm.core.persistence.reverse.lazy.ddd.DefaultDDDLazyInfrastructurePersistence;
import org.wu.framework.lazy.orm.database.lambda.stream.lambda.LazyLambdaStream;
import org.wu.framework.lazy.orm.database.lambda.stream.wrapper.LazyWrappers;
import org.wu.framework.lazy.orm.web.plus.AbstractLazyCrudRepository;
import org.wu.framework.web.response.Result;
import org.wu.framework.web.response.ResultFactory;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * describe 接口
 *
 * @author Jia wei Wu
 * @date 2023/05/17 11:19 晚上
 * @see DefaultDDDLazyInfrastructurePersistence
 **/
@Repository
public class SysInterfaceRepositoryImpl implements SysInterfaceRepository, CommandLineRunner {

    @Autowired
    LazyLambdaStream lazyLambdaStream;


    @Autowired
    private ApplicationContext applicationContext;

    /**
     * describe 新增接口
     *
     * @param
     * @return
     * @exception/throws
     * @author Jia wei Wu
     * @date 2023/05/17 11:19 晚上
     **/

    @Override
    public Result<SysInterface> story(SysInterface sysInterface_) {
        SysInterfaceDO interface_DO = SysInterfaceConverter.fromInterface(sysInterface_);
        lazyLambdaStream.upsert(interface_DO);
        return ResultFactory.successOf();
    }

    /**
     * describe 查询单个接口
     *
     * @param
     * @return
     * @exception/throws
     * @author Jia wei Wu
     * @date 2023/05/17 11:19 晚上
     **/

    @Override
    public Result<SysInterface> findOne(SysInterface sysInterface_) {
        SysInterfaceDO interface_DO = SysInterfaceConverter.fromInterface(sysInterface_);
        SysInterface sysInterface_One = lazyLambdaStream.selectOne(LazyWrappers.lambdaWrapperBean(interface_DO), SysInterface.class);
        return ResultFactory.successOf(sysInterface_One);
    }

    /**
     * describe 查询多个接口
     *
     * @param
     * @return
     * @exception/throws
     * @author Jia wei Wu
     * @date 2023/05/17 11:19 晚上
     **/

    @Override
    public Result<List<SysInterface>> findList(SysInterface sysInterface_) {
        SysInterfaceDO interface_DO = SysInterfaceConverter.fromInterface(sysInterface_);
        List<SysInterface> sysInterface_List = lazyLambdaStream.selectList(LazyWrappers.lambdaWrapperBean(interface_DO), SysInterface.class);
        return ResultFactory.successOf(sysInterface_List);
    }

    /**
     * describe 删除接口
     *
     * @param
     * @return
     * @exception/throws
     * @author Jia wei Wu
     * @date 2023/05/17 11:19 晚上
     **/

    @Override
    public Result<SysInterface> delete(SysInterface sysInterface_) {
        SysInterfaceDO interface_DO = SysInterfaceConverter.fromInterface(sysInterface_);
        //  lazyLambdaStream.remove(interface_DO);
        return ResultFactory.successOf();
    }

    /**
     * describe 扫描当前项目中接口
     *
     * @param
     * @return
     * @author Jia wei Wu
     * @date 2022/1/31 00:09
     **/
    public List<SysInterface> scanInterface() {
        final String applicationName = applicationContext.getApplicationName();
        final Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(RequestMapping.class);

        List<SysInterface> sysInterfaceList = new ArrayList<>();

        beansWithAnnotation.values().stream().map(Object::getClass).forEach(interfaceProviderClass -> {
            final RequestMapping mergedAnnotation = AnnotatedElementUtils.getMergedAnnotation(interfaceProviderClass, RequestMapping.class);
            final String[] parentPath = mergedAnnotation.value();
            String[] tag = new String[0];
            if (AnnotatedElementUtils.hasAnnotation(interfaceProviderClass, Api.class)) {
                final Api api = AnnotatedElementUtils.getMergedAnnotation(interfaceProviderClass, Api.class);
                tag = new String[]{api.tags()};
            }

            final Method[] methods = interfaceProviderClass.getMethods();

            for (Method method : methods) {
                final boolean hasAnnotation = AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class);
                if (hasAnnotation) {
                    final RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(method, RequestMapping.class);
                    final SysInterface anSysInterface = new SysInterface();
                    anSysInterface.setApplicationName(applicationName);
                    anSysInterface.setPath(Arrays.asList(requestMapping.path()));
                    if (ObjectUtils.isEmpty(requestMapping.method())) {
                        anSysInterface.setRequestMethods(Arrays.asList(RequestMethod.values()));
                    } else {
                        anSysInterface.setRequestMethods(Arrays.asList(requestMapping.method()));
                    }
                    anSysInterface.setParentPath(Arrays.asList(parentPath));
                    final boolean hasApiOperation = AnnotatedElementUtils.hasAnnotation(method, ApiOperation.class);
                    if (hasApiOperation) {
                        final ApiOperation apiOperation = AnnotatedElementUtils.findMergedAnnotation(method, ApiOperation.class);
                        anSysInterface.setDescription(apiOperation.value());
                        final List<String> tags = new ArrayList<>();
                        if (!ObjectUtils.isEmpty(tag)) {
                            tags.addAll(Arrays.asList(tag));
                        }
                        tags.addAll(Arrays.asList(apiOperation.tags()));
                        anSysInterface.setTag(tags);
                    } else {
                        anSysInterface.setTag(Arrays.asList(tag));
                    }
                    sysInterfaceList.add(anSysInterface);
                }
            }
        });
        return sysInterfaceList;
    }

    @Override
    public void run(String... args) {
        try {
            final List<SysInterface> sysInterfaceList = scanInterface();
            sysInterfaceList.stream().parallel().forEach(lazyLambdaStream::upsert);
            lazyLambdaStream.upsert(sysInterfaceList);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}